﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

using G.Model;
using GameControls;

namespace GameDesignControls
{
    public partial class GameTreeControl : UserControl
    {
        private GameDisplayer _GameDisplayer;
        private TreeNode _ElementsNode;
        
        public GameTreeControl()
        {
            InitializeComponent();
        }
        
        private void OnChange()
        {
            SyncGame();
        }

        void OnTaskEvent(GameTaskDef subject)
        {
            SyncGame();
        }

        void OnElementRemovedEvent(GameElementDef subject)
        {
            SyncGame();
        }

        void OnElementAddedEvent(GameElementDef subject)
        {
            SyncGame();
        }

        public GameDisplayer GameDisplayer
        {
            get { return _GameDisplayer; }
            set
            {
                if (_GameDisplayer != value)
                {
                    if (_GameDisplayer != null)
                    {
                        UnWatch(_GameDisplayer);
                    }
                    _GameDisplayer = value;
                    if (value != null)
                    {
                        Watch(value);
                        SyncGame(value.GameDef);
                    }
                    else
                    {
                        this.treeView1.Nodes.Clear();
                    }
                }
            }
        }

        private void Watch(GameDisplayer pGameDisplayer)
        {
            pGameDisplayer.ActiveObject.SelectedEvent += OnElementSelected;
            
            GameSpaceDef game = pGameDisplayer.GameDef;
            game.GamePlayerDefs.PlayersChangedEvent += OnChange;
            game.GameElementDefs.ElementAddedEvent += OnElementAddedEvent;
            game.GameElementDefs.ElementRemovedEvent += OnElementRemovedEvent;
            game.GameTaskDefs.TaskAddedEvent += OnTaskEvent;
            game.GameTaskDefs.TaskRemovedEvent += OnChange;
            game.GameTaskDefs.TaskChangedEvent += OnChange;
        }
        
        private void OnElementSelected(object obj)
        {
            if (obj is HasName)
            {
                HasName test = (HasName)obj;
                foreach (TreeNode node in _ElementsNode.Nodes) {
                    if (node.Tag is HasName)
                    {
                        HasName hasName = (HasName)node.Tag;
                        Console.WriteLine(hasName.Name + " " + test.Name);
                        if (hasName.Name == test.Name)
                        {
                            this.treeView1.SelectedNode = node;
                            break;
                        }
                    }
                }
            }
        }

        private void UnWatch(GameDisplayer pGameDisplayer)
        {
            pGameDisplayer.ActiveObject.SelectedEvent -= OnElementSelected;
            
            GameSpaceDef game = pGameDisplayer.GameDef;
            game.GamePlayerDefs.PlayersChangedEvent -= OnChange;
            game.GameElementDefs.ElementAddedEvent -= OnElementAddedEvent;
            game.GameElementDefs.ElementRemovedEvent -= OnElementRemovedEvent;
            game.GameTaskDefs.TaskAddedEvent -= OnTaskEvent;
            game.GameTaskDefs.TaskRemovedEvent -= OnChange;
            game.GameTaskDefs.TaskChangedEvent -= OnChange;
        }
        
        private void OnObjectSelected(object obj)
        {
            SyncGame();
        }

        void SyncGame()
        {
            if (_GameDisplayer != null) 
            {
                SyncGame(_GameDisplayer.GameDef);
            } 
            else 
            {
                this.treeView1.Nodes.Clear();
            }
        }

        private void SyncGame(GameSpaceDef game)
        {
            this.treeView1.BeginUpdate();
            TreeNode root;
            TreeNode playersNode;
            TreeNode globalNode;
            TreeNode tasksNode;
            if (this.treeView1.Nodes.Count == 0)
            {
                root = new TreeNode();
                root.Text = "Game";
                root.Tag = game;
                root.ImageIndex = 2;
                root.SelectedImageIndex = 4;

                this.treeView1.Nodes.Clear();
                this.treeView1.Nodes.Add(root);
                
                playersNode = root.Nodes.Add("Players", "Players");
                playersNode.Tag = game.GamePlayerDefs;
                playersNode.ImageIndex = 0;
                playersNode.SelectedImageIndex = 4;
                
                _ElementsNode = root.Nodes.Add("Elements", "Elements");
                _ElementsNode.Tag = game.GameElementDefs;
                _ElementsNode.ImageIndex = 0;
                _ElementsNode.SelectedImageIndex = 4;
                
                tasksNode = root.Nodes.Add("Tasks", "Tasks");
                tasksNode.Tag = game.GameTaskDefs;
                tasksNode.ImageIndex = 0;
                tasksNode.SelectedImageIndex = 4;
                
                globalNode = new TreeNode();
                globalNode = root.Nodes.Add("Global", "Global");
                globalNode.Tag = game.GlobalDef;
                globalNode.SelectedImageIndex = 4;

                root.ExpandAll();
            }
            else
            {
                root = this.treeView1.Nodes[0];
                playersNode = root.Nodes[0];
                _ElementsNode = root.Nodes[1];
                tasksNode = root.Nodes[2];
            }

            Sync<GamePlayerDef>(game, playersNode, game.GamePlayerDefs, 1);
            Sync(game, _ElementsNode, game.GameElementDefs, 3);
            Sync(game, tasksNode, game.GameTaskDefs, 3);

            this.treeView1.EndUpdate();
        }

        private static void Sync<T>(GameSpaceDef game, TreeNode parentNode,
                                    ICollection<T> items, int imageIndex)
        {
            List<TreeNode> remove = new List<TreeNode>();
            foreach (TreeNode node in parentNode.Nodes)
            {
                bool found = false;
                foreach (HasName item in items)
                {
                    if (item.Name == node.Name)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    remove.Add(node);
                }
            }

            foreach (TreeNode node in remove)
            {
                parentNode.Nodes.Remove(node);
            }
            
            foreach (HasName item in items)
            {
                if (item.Name == "Nothing")
                {
                    continue;
                }
                if (!parentNode.Nodes.ContainsKey(item.Name))
                {
                    TreeNode node = parentNode.Nodes.Add(item.Name, item.Name);
                    node.Text = item.Name;
                    node.Tag = item;
                    node.ImageIndex = imageIndex;
                    node.SelectedImageIndex = 4;
                    parentNode.ExpandAll();
                }
            }

        }
        
        void TreeView1BeforeSelect(object sender, TreeViewCancelEventArgs e)
        {
            _GameDisplayer.ActiveObject.SelectedObject = e.Node.Tag;
        }
    }
}
